/*
 *  Copyright:  (C) 2018 LingYun IoT System Studio
 *              All rights reserved.
 *
 *  File name:  socket_server.c
 *Description:  Socket server program,using getopt().
 *
 *    Version:  1.1
 *     Author:  Guo Wenxue <guowenxue@gmail.com>
 *		        Copied by Zhu Tianyin <zhuty_cn@163.com>
 *  ChangeLog:  1.0  Release initial version in 2018.
 *              1.1  Copy and change some details on "01/08/2021".
 */
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <getopt.h>

#define MSG_STR "This is a message from server!\n"

void print_usage(char *progname)
{
    printf("%s usage: \n", progname);
	printf("-p(--port): sepcify server listen port.\n");
	printf("-h(--Help): print this help information.\n");

	return ;
}

int main(int argc, char **argv)
{
	int                  sockfd = -1;
	int                  rv = -1;
	struct sockaddr_in   servaddr;
	struct sockaddr_in   cliaddr;
	socklen_t            len;
	int                  port = 0;
	char                 buf[1024];
	int                  clifd;
	int                  ch;
	int                  on = 1;

       	struct option        opts[] = {
		{"port", required_argument, NULL, 'p'},
		{"help", no_argument, NULL, 'h'},
		{NULL, 0, NULL, 0}
	};

	while( (ch=getopt_long(argc, argv, "p:h", opts, NULL)) != -1 ) 
	{
		switch(ch)
		{
			case 'p':
				port=atoi(optarg);
				break;

			case 'h':
				print_usage(argv[0]);
				return 0;
		}

	}

	if( !port )
	{
		print_usage(argv[0]);
		return 0;
	}

	sockfd=socket(AF_INET, SOCK_STREAM, 0);
	if(sockfd < 0)
	{
		printf("Create socket failure: %s\n", strerror(errno));
		return -1;
	}
	printf("Create socket[%d] successfully!\n", sockfd);

	setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

	memset(&servaddr, 0, sizeof(servaddr));
	servaddr.sin_family=AF_INET;
	servaddr.sin_port = htons(port);
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	//inet_aton("192.168.0.16", &servaddr.sin_addr);

	rv=bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
	if(rv < 0)
	{
		printf("Socket[%d] bind on port[%d] failure: %s\n", 
				sockfd, port, strerror(errno));
		return -2;
	}

	listen(sockfd, 13);
	printf("Start to listen on port [%d]\n", port);

	while(1)
	{ 
		printf("Start accept new client incoming...\n");

		clifd=accept(sockfd, (struct sockaddr *)&cliaddr, &len);
		if(clifd < 0)
		{
			printf("Accept new client failure: %s\n", strerror(errno));
			continue;
		}

		printf("Accept new client[%s:%d] successfully\n", 
				inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));

		memset(buf, 0, sizeof(buf));
		rv=read(clifd, buf, sizeof(buf));
	       	if( rv < 0)
	       	{
		       	printf("Read data from client sockfd[%d] failure: %s\n", 
					clifd, strerror(errno));
			close(clifd);
			continue;
	       	}
	       	else if( rv == 0)
	       	{ 
			printf("Socket[%d] get disconnected\n", clifd);
			close(clifd);
			continue;
		}
		else if( rv > 0 )
		{
			printf("Read %d bytes data from Server: %s\n", 
					rv, buf);
		}

		rv=write(clifd, MSG_STR, strlen(MSG_STR));
	       	if(rv < 0)
	       	{
		       	printf("Write to client by sockfd[%d] failure: %s\n", 
					sockfd, strerror(errno));
			close(clifd);
			continue;
	       	}

		printf("Close client socket[%d]\n", clifd);
		close(clifd);
	}


	close(sockfd);
}
